package com.mydemo.springlearning.functions.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
@Slf4j
public class AopTest1 {
    /**
     * 重点讲解下execution表达式部分，execution是执行的意思。
     * public * com.cx.timer...看起来非常复杂，晦涩难懂。
     * 其实这里就是一个方法名的定义：作用域 返回类型 方法名（参数..）。
     * 其中上图的作用域是：public返回类型：* （* 表示Object类型）方法名(参数..) ：
     * com.cx.timer.aop.controller是指具体的包名；
     * .* 表示 该包名下的所有的类；
     * *(..) *表示类下所有的方法，.. 不限定参数。
     */
    @Pointcut("execution(public * com.mydemo.springlearning.functions.CRUDdemo.byxml.controller.TestController.testAdd(..))")
    public void point() {
    }

    @Before("point()")
    public void before(JoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        log.debug("URL:" + request.getRequestURL().toString());
        log.debug("RemoteIP:" + request.getRemoteAddr());
        log.debug("LocalIP:" + request.getLocalAddr());
    }

    @AfterReturning(returning = "obj", pointcut = "point()")
    public void afterReturn(Object obj) {
        log.debug("obj:{}", obj);
    }

    @Around(value = "point()")
    public Object around(ProceedingJoinPoint point) {


        //1.这里获取到所有的参数值的数组
        Object[] args = point.getArgs();
        //传入参数名+execution(Result com.dsfa.teas.classes.web.student.controller.StudentController.stuImport(Map))
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;

        //2.最关键的一步:通过这获取到方法的所有参数名称的字符串数组
        String[] parameterNames = methodSignature.getParameterNames();


        System.out.println("切入前");
        Object o = null;
        try {
            o = point.proceed();

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        System.out.println("切入后");
        return o;

    }

}
